home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mgr / sparcmgr / demo2.zoo / demo / ex / ex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-04-24  |  11.0 KB  |  518 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6.  
  7. #ifndef lint
  8. char *copyright =
  9. "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  10.  All rights reserved.\n";
  11. #endif not lint
  12.  
  13. #ifndef lint
  14. static char *sccsid = "@(#)ex.c    7.6 (Berkeley) 3/9/87; 1.2 (Bellcore)    87/04/24";
  15. #endif not lint
  16.  
  17. #include "ex.h"
  18. #include "ex_argv.h"
  19. #include "ex_temp.h"
  20. #include "ex_tty.h"
  21.  
  22. #ifdef TRACE
  23. #ifdef    vms
  24. char    tttrace[]    = { 't','r','a','c','e','.','l','i','s' };
  25. #else
  26. char    tttrace[]    = { '/','d','e','v','/','t','t','y','x','x',0 };
  27. #endif
  28. #endif
  29.  
  30. /*
  31.  * The code for ex is divided as follows:
  32.  *
  33.  * ex.c            Entry point and routines handling interrupt, hangup
  34.  *            signals; initialization code.
  35.  *
  36.  * ex_addr.c        Address parsing routines for command mode decoding.
  37.  *            Routines to set and check address ranges on commands.
  38.  *
  39.  * ex_cmds.c        Command mode command decoding.
  40.  *
  41.  * ex_cmds2.c        Subroutines for command decoding and processing of
  42.  *            file names in the argument list.  Routines to print
  43.  *            messages and reset state when errors occur.
  44.  *
  45.  * ex_cmdsub.c        Subroutines which implement command mode functions
  46.  *            such as append, delete, join.
  47.  *
  48.  * ex_data.c        Initialization of options.
  49.  *
  50.  * ex_get.c        Command mode input routines.
  51.  *
  52.  * ex_io.c        General input/output processing: file i/o, unix
  53.  *            escapes, filtering, source commands, preserving
  54.  *            and recovering.
  55.  *
  56.  * ex_put.c        Terminal driving and optimizing routines for low-level
  57.  *            output (cursor-positioning); output line formatting
  58.  *            routines.
  59.  *
  60.  * ex_re.c        Global commands, substitute, regular expression
  61.  *            compilation and execution.
  62.  *
  63.  * ex_set.c        The set command.
  64.  *
  65.  * ex_subr.c        Loads of miscellaneous subroutines.
  66.  *
  67.  * ex_temp.c        Editor buffer routines for main buffer and also
  68.  *            for named buffers (Q registers if you will.)
  69.  *
  70.  * ex_tty.c        Terminal dependent initializations from termcap
  71.  *            data base, grabbing of tty modes (at beginning
  72.  *            and after escapes).
  73.  *
  74.  * ex_unix.c        Routines for the ! command and its variations.
  75.  *
  76.  * ex_v*.c        Visual/open mode routines... see ex_v.c for a
  77.  *            guide to the overall organization.
  78.  */
  79.  
  80. /*
  81.  * Main procedure.  Process arguments and then
  82.  * transfer control to the main command processing loop
  83.  * in the routine commands.  We are entered as either "ex", "edit", "vi"
  84.  * or "view" and the distinction is made here.  Actually, we are "vi" if
  85.  * there is a 'v' in our name, "view" is there is a 'w', and "edit" if
  86.  * there is a 'd' in our name.  For edit we just diddle options;
  87.  * for vi we actually force an early visual command.
  88.  */
  89. main(ac, av)
  90.     register int ac;
  91.     register char *av[];
  92. {
  93. #ifdef EXSTRINGS
  94.     char *erpath = EXSTRINGS;
  95. #endif
  96.     register char *cp;
  97.     register int c;
  98.     bool recov = 0;
  99.     bool ivis;
  100.     bool itag = 0;
  101.     bool fast = 0;
  102.     extern int onemt();
  103. #ifdef UNIX_SBRK
  104.     extern char *sbrk();
  105. #else
  106.     extern char *malloc();
  107. #endif
  108. #ifdef TRACE
  109.     register char *tracef;
  110. #endif
  111. #ifdef    vms
  112.     char termtype[20];
  113. #endif
  114.  
  115.     /*
  116.      * Immediately grab the tty modes so that we wont
  117.      * get messed up if an interrupt comes in quickly.
  118.      */
  119.     ex_gTTY(1);
  120. #ifndef USG3TTY
  121.     normf = tty.sg_flags;
  122. #else
  123.     normf = tty;
  124. #endif
  125.     ppid = getpid();
  126.     /*
  127.      * Defend against d's, v's, w's, and a's in directories of
  128.      * path leading to our true name.
  129.      */
  130. #ifndef    vms
  131.     av[0] = tailpath(av[0]);
  132. #else
  133.     /*
  134.      * This program has to be invoked by using the following
  135.      * string definitions:
  136.      *
  137.      * vi == "$dir:ex.exe vi"
  138.      * view == "$dir:ex.exe view"
  139.      * ex == "$dir:ex.exe ex"
  140.      * edit == "$dir:ex.exe edit"
  141.      */
  142.     ac--;
  143.     av++;
  144. #endif
  145.  
  146.     /*
  147.      * Figure out how we were invoked: ex, edit, vi, view.
  148.      */
  149.     ivis = any('v', av[0]);    /* "vi" */
  150.     if (any('w', av[0]))    /* "view" */
  151.         value(READONLY) = 1;
  152.     if (any('d', av[0])) {    /* "edit" */
  153.         value(OPEN) = 0;
  154.         value(REPORT) = 1;
  155.         value(MAGIC) = 0;
  156.     }
  157.  
  158. #ifdef EXSTRINGS
  159.     /*
  160.      * For debugging take files out of . if name is a.out.
  161.      */
  162.     if (av[0][0] == 'a')
  163.         erpath = tailpath(erpath);
  164. #endif
  165.     /*
  166.      * Open the error message file.
  167.      */
  168.     draino();
  169. #ifdef EXSTRINGS
  170.     erfile = open(erpath+4, 0);
  171.     if (erfile < 0) {
  172.         erfile = open(erpath, 0);
  173.     }
  174. #endif
  175.     pstop();
  176.  
  177.     /*
  178.      * Initialize interrupt handling.
  179.      */
  180.     oldhup = signal(SIGHUP, SIG_IGN);
  181.     if (oldhup == SIG_DFL)
  182.         signal(SIGHUP, onhup);
  183.     oldquit = signal(SIGQUIT, SIG_IGN);
  184.     ruptible = signal(SIGINT, SIG_IGN) == SIG_DFL;
  185.     if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
  186.         signal(SIGTERM, onhup);
  187.     if (signal(SIGEMT, SIG_IGN) == SIG_DFL)
  188.         signal(SIGEMT, onemt);
  189.  
  190.     /*
  191.      * Process flag arguments.
  192.      */
  193.     ac--, av++;
  194.     while (ac && av[0][0] == '-') {
  195.         c = av[0][1];
  196.         if (c == 0) {
  197.             hush = 1;
  198.             value(AUTOPRINT) = 0;
  199.             fast++;
  200.         } else switch (c) {
  201.  
  202.         case 'R':
  203.             value(READONLY) = 1;
  204.             break;
  205.  
  206. #ifdef TRACE
  207.         case 'T':
  208.             if (av[0][2] == 0)
  209.                 tracef = "trace";
  210.             else {
  211.                 tracef = tttrace;
  212.                 tracef[8] = av[0][2];
  213.                 if (tracef[8])
  214.                     tracef[9] = av[0][3];
  215.                 else
  216.                     tracef[9] = 0;
  217.             }
  218.             trace = fopen(tracef, "w");
  219. #define tracbuf NULL
  220.             if (trace == NULL)
  221.                 ex_printf("Trace create error\n");
  222.             else
  223.                 setbuf(trace, tracbuf);
  224.             break;
  225.  
  226. #endif
  227.  
  228. #ifdef LISPCODE
  229.         case 'l':
  230.             value(LISP) = 1;
  231.             value(SHOWMATCH) = 1;
  232.             break;
  233. #endif
  234.  
  235.         case 'r':
  236.             recov++;
  237.             break;
  238.  
  239.         case 't':
  240.             if (ac > 1 && av[1][0] != '-') {
  241.                 ac--, av++;
  242.                 itag = 1;
  243.                 /* BUG: should check for too long tag. */
  244.                 CP(lasttag, av[0]);
  245.             }
  246.             break;
  247.  
  248.         case 'v':
  249.             ivis = 1;
  250.             break;
  251.  
  252.         case 'w':
  253.             defwind = 0;
  254.             if (av[0][2] == 0) defwind = 3;
  255.             else for (cp = &av[0][2]; isdigit(*cp); cp++)
  256.                 defwind = 10*defwind + *cp - '0';
  257.             break;
  258.  
  259. #ifdef CRYPT
  260.         case 'x':
  261.             /* -x: encrypted mode */
  262.             xflag = 1;
  263.             break;
  264. #endif
  265.  
  266.         default:
  267.             smerror("Unknown option %s\n", av[0]);
  268.             break;
  269.         }
  270.         ac--, av++;
  271.     }
  272.  
  273. #ifdef SIGTSTP
  274.     if (!hush && signal(SIGTSTP, SIG_IGN) == SIG_DFL)
  275.         signal(SIGTSTP, onsusp), dosusp++;
  276. #endif
  277.  
  278.     if (ac && av[0][0] == '+') {
  279.         firstpat = &av[0][1];
  280.         ac--, av++;
  281.     }
  282.  
  283. #ifdef CRYPT
  284.     if(xflag){
  285.         key = getpass(KEYPROMPT);
  286.         kflag = crinit(key, perm);
  287.     }
  288. #endif
  289.  
  290.     /*
  291.      * If we are doing a recover and no filename
  292.      * was given, then execute an exrecover command with
  293.      * the -r option to type out the list of saved file names.
  294.      * Otherwise set the remembered file name to the first argument
  295.      * file name so the "recover" initial command will find it.
  296.      */
  297.     if (recov) {
  298.         if (ac == 0) {
  299.             ppid = 0;
  300.             setrupt();
  301.             execl(EXRECOVER, "exrecover", "-r", 0);
  302.             filioerr(EXRECOVER);
  303.             ex_exit(1);
  304.         }
  305.         CP(savedfile, *av++), ac--;
  306.     }
  307.  
  308.     /*
  309.      * Initialize the argument list.
  310.      */
  311.     argv0 = av;
  312.     argc0 = ac;
  313.     args0 = av[0];
  314.     erewind();
  315.  
  316.     /*
  317.      * Initialize a temporary file (buffer) and
  318.      * set up terminal environment.  Read user startup commands.
  319.      */
  320.     if (setexit() == 0) {
  321.         setrupt();
  322.         intty = isatty(0);
  323.         value(PROMPT) = intty;
  324. #ifndef    vms
  325.         if (cp = getenv("SHELL"))
  326. #else
  327.         if (cp = getlog("SHELL"))
  328. #endif
  329.             CP(shell, cp);
  330.         if (fast || !intty)
  331.             setterm("dumb");
  332.         else {
  333.             gettmode();
  334. #ifndef    vms
  335.             if ((cp = getenv("TERM")) != 0 && *cp)
  336.                 setterm(cp);
  337. #else
  338.             if ((cp = getlog("TERM")) != 0 && *cp) {
  339.                 /*
  340.                  * Can't just use it directly since getlog
  341.                  * returns a pointer to a static buffer that
  342.                  * tgetent() will eventually use
  343.                  */
  344.                 CP(termtype, cp);
  345.                 setterm(termtype);
  346.             }
  347. #endif
  348.         }
  349.     }
  350.     if (setexit() == 0 && !fast && intty) {
  351. #ifndef    vms
  352.         if ((globp = getenv("EXINIT")) && *globp)
  353. #else
  354.         if ((globp = getlog("EXINIT")) && *globp)
  355. #endif
  356.             commands(1,1);
  357.         else {
  358.             globp = 0;
  359.             if ((cp = getenv("HOME")) != 0 && *cp) {
  360.                 (void) strcat(strcpy(genbuf, cp), "/.exrc");
  361.                 if (iownit(genbuf))
  362.                     source(genbuf, 1);
  363.             }
  364.         }
  365.         /*
  366.          * Allow local .exrc too.  This loses if . is $HOME,
  367.          * but nobody should notice unless they do stupid things
  368.          * like putting a version command in .exrc.  Besides,
  369.          * they should be using EXINIT, not .exrc, right?
  370.          */
  371.          if (iownit(".exrc"))
  372.             source(".exrc", 1);
  373.     }
  374. #ifdef    UNIX_SBRK
  375.     /*
  376.      * Initialize end of core pointers.
  377.      * Normally we avoid breaking back to fendcore after each
  378.      * file since this can be expensive (much core-core copying).
  379.      * If your system can scatter load processes you could do
  380.      * this as ed does, saving a little core, but it will probably
  381.      * not often make much difference.
  382.      */
  383.     fendcore = (line *) sbrk(0);
  384.     endcore = fendcore - 2;
  385. #else
  386.     /*
  387.      * Allocate all the memory we will ever use in one chunk.
  388.      * This is for system such as VMS where sbrk() does not
  389.      * guarantee that the memory allocated beyond the end is
  390.      * consecutive.  VMS's RMS does all sorts of memory allocation
  391.      * and screwed up ex royally because ex assumes that all
  392.      * memory up to "endcore" belongs to it and RMS has different
  393.      * ideas.
  394.      */
  395.     fendcore = (line *) malloc((unsigned)
  396.         value(LINELIMIT) * sizeof (line *));
  397.     if (fendcore == NULL) {
  398.         lprintf("ex: cannot handle %d lines\n", value(LINELIMIT));
  399.         lprintf("ex: set \"linelimit\" lower\n");
  400.         flush();
  401.         ex_exit(1);
  402.     }
  403.     endcore = fendcore + (value(LINELIMIT) - 1);
  404. #endif
  405.     init();    /* moved after prev 2 chunks to fix directory option */
  406.  
  407.     /*
  408.      * Initial processing.  Handle tag, recover, and file argument
  409.      * implied next commands.  If going in as 'vi', then don't do
  410.      * anything, just set initev so we will do it later (from within
  411.      * visual).
  412.      */
  413.     if (setexit() == 0) {
  414.         if (recov)
  415.             globp = "recover";
  416.         else if (itag)
  417.             globp = ivis ? "tag" : "tag|p";
  418.         else if (argc)
  419.             globp = "next";
  420.         if (ivis)
  421.             initev = globp;
  422.         else if (globp) {
  423.             inglobal = 1;
  424.             commands(1, 1);
  425.             inglobal = 0;
  426.         }
  427.     }
  428.  
  429.     /*
  430.      * Vi command... go into visual.
  431.      * Strange... everything in vi usually happens
  432.      * before we ever "start".
  433.      */
  434.     if (ivis) {
  435.         /*
  436.          * Don't have to be upward compatible with stupidity
  437.          * of starting editing at line $.
  438.          */
  439.         if (dol > zero)
  440.             dot = one;
  441.         globp = "visual";
  442.         if (setexit() == 0)
  443.             commands(1, 1);
  444.     }
  445.  
  446.     /*
  447.      * Clear out trash in state accumulated by startup,
  448.      * and then do the main command loop for a normal edit.
  449.      * If you quit out of a 'vi' command by doing Q or ^\,
  450.      * you also fall through to here.
  451.      */
  452.     seenprompt = 1;
  453.     ungetchar(0);
  454.     globp = 0;
  455.     initev = 0;
  456.     setlastchar('\n');
  457.     setexit();
  458.     commands(0, 0);
  459.     cleanup(1);
  460.     ex_exit(0);
  461. }
  462.  
  463. /*
  464.  * Initialization, before editing a new file.
  465.  * Main thing here is to get a new buffer (in fileinit),
  466.  * rest is peripheral state resetting.
  467.  */
  468. init()
  469. {
  470.     register int i;
  471.  
  472.     fileinit();
  473.     dot = zero = truedol = unddol = dol = fendcore;
  474.     one = zero+1;
  475.     undkind = UNDNONE;
  476.     chng = 0;
  477.     edited = 0;
  478.     for (i = 0; i <= 'z'-'a'+1; i++)
  479.         names[i] = 1;
  480.     anymarks = 0;
  481. #ifdef CRYPT
  482.         if(xflag) {
  483.                 xtflag = 1;
  484.                 makekey(key, tperm);
  485.         }
  486. #endif
  487. }
  488.  
  489. /*
  490.  * Return last component of unix path name p.
  491.  */
  492. char *
  493. tailpath(p)
  494. register char *p;
  495. {
  496.     register char *r;
  497.  
  498.     for (r=p; *p; p++)
  499.         if (*p == '/')
  500.             r = p+1;
  501.     return(r);
  502. }
  503.  
  504. /*
  505.  * Check ownership of file.  Return nonzero if it exists and is owned by the
  506.  * user or the option sourceany is used
  507.  */
  508. iownit(file)
  509. char *file;
  510. {
  511.     struct stat sb;
  512.  
  513.     if (stat(file, &sb) == 0 && (value(SOURCEANY) || sb.st_uid == getuid()))
  514.         return(1);
  515.     else
  516.         return(0);
  517. }
  518.